# JS 中的 Event Loop (事件循环)
# 微任务与宏任务
JS 执行时,遇到异步任务则放入微任务或宏任务异步队列中,将同步代码执行完毕之后再去执行异步队列中的代码。先执行微任务队列,微任务队列执行完毕后再执行宏任务队列。
微任务队列和宏任务队列均遵循:先入先执行的原则
# 微任务
- Promise.prototype.then()
- process.nextTick()
# 宏任务
- setTimeout()
- setInterVal()
# async / await
async 函数本身并不是异步任务,而是根据函数中执行的代码来确定放入宏任务或微任务中。
const fn = async () => {
console.log(1)
}
fn()
console.log(2)
// 1 2
1
2
3
4
5
6
7
2
3
4
5
6
7
const fn = async () => {
console.log(1)
setTimeout(() => {
console.log(2)
}, 0);
}
fn()
console.log(3)
// 1 3 2
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
await 执行时,await 的函数会立即执行,此函数执行完毕后,再将 await 之后的代码放入微任务队列中。
const fun = async () => {
console.log(1)
}
const fn = async () => {
console.log(2)
await fun()
console.log(3)
}
fn()
console.log(4)
// 2 1 4 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
const fn = async () => {
console.log(1)
setTimeout(() => {
console.log(2)
}, 0);
}
fn()
console.log(3)
// 1 3 2
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
const fun = async () => {
console.log(1)
setTimeout(() => {
console.log('setTimeout')
}, 0);
new Promise(resolve => {
console.log(2)
resolve()
}).then(() => {
console.log(3)
})
}
const fn = async () => {
console.log(4)
await fun()
console.log(5)
}
fn()
console.log(6)
// 4 1 2 6 3 5 'setTimeout'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 例一
setTimeout(() => {
console.log(1)
}, 0);
new Promise((resolve) => {
console.log(2)
resolve()
}).then(() => {
console.log(3)
})
setTimeout(() => {
console.log(4)
}, 0);
console.log(5)
/*
2
5
3
1
4
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 例二
setTimeout(() => {
console.log(1)
new Promise((resolve) => {
console.log(2)
resolve()
}).then(() => {
console.log(3)
})
}, 0);
new Promise((resolve) => {
console.log(4)
resolve()
}).then(() => {
console.log(5)
})
setTimeout(() => {
console.log(6)
new Promise((resolve) => {
console.log(7)
resolve()
}).then(() => {
console.log(8)
})
}, 0);
console.log(9)
/*
// node 运行结果
4
9
5
1
2
6
7
3
8
*/
/*
// Chrome 运行结果
4
9
5
1
2
3
6
7
8
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
以上结果在浏览器和Node中不相同,证明两者对嵌套的异步队列执行顺序不一样。
在Node中,将微任务执行完后,然后执行宏任务,即使在宏任务中又有微任务插入微任务异步队列,但也会将本次的所有宏任务执行完毕之后,再去执行微任务。
在浏览器中,将微任务执行完后,然后执行宏任务,但每一个宏任务完后,不会先执行下一个宏任务,而是再次去查看有没有微任务需要执行,有的话则将微任务队列执行完毕,再回到宏任务队列执行下一个宏任务。
# 例三
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
/*
script start
async1 start
async2
promise1
script end
promise2
async1 end
setTimeout
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39